/*
MujMail - Simple mail client for J2ME
Copyright (C) 2003 Petr Spatka <petr.spatka@centrum.cz>
Copyright (C) 2005 Pavel Machek <pavel@ucw.cz>
Copyright (C) 2006 Nguyen Son Tung <n.sontung@gmail.com>
Copyright (C) 2006 Martin Stefan <martin.stefan@centrum.cz>
Copyright (C) 2008 David Hauzar <david.hauzar.mujmail@gmail.com>
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package mujmail;


import com.sun.lwuit.events.ActionEvent;
import java.util.Enumeration;
import java.util.Hashtable;
import lcduilwuit.*;
import javax.microedition.midlet.MIDlet;
import mujmail.account.AccountSettings;
import mujmail.account.MailAccount;
import com.sun.lwuit.Font;
//#ifdef MUJMAIL_SYNC
//# import mujmail.account.MailAccountPrimary;
//#endif
import mujmail.protocols.SMTP;
import mujmail.util.Functions;
//#ifdef MUJMAIL_SEARCH
//import mujmail.search.SearchBox;
//#endif
//#ifdef MUJMAIL_SYNC
//# import mujmail.account.Sync;
//#endif
//#ifdef MUJMAIL_USR_FOLDERS
import mujmail.mailboxes.BoxList;
//#endif
//#ifdef MUJMAIL_DEBUG_CONSOLE
//# import mujmail.debug.DebugConsole;
//#endif
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
import LwuitUI.*;
import com.sun.lwuit.events.ActionListener;
public class MujMail extends MIDlet implements /*CommandListener,*/ ActionListener {
    static{
         Lang.loadSavedLang();
    }
    /** Flag signals if we want to print debug prints */
    private static final boolean DEBUG = false;

    public static String VERSION ;//= "v1.08.08";
    public static String  BUILD;// = 20090402;

    public static Properties props;

    //private Lang language = new Lang();
    private MyDisplay myDisplay = new MyDisplay(this);
    public MyAlert alert;// = new MyAlert(this);
    private Settings settings;// = new Settings(this);
    private  AccountSettings accountSettings;// = new AccountSettings(this);
  //  private AddressBook addressBook;// = new AddressBook(this);
    public final OutBox outBox;
    final PersistentBox sentBox;
    //#ifdef MUJMAIL_SEARCH
 //   final private SearchBox searchBox;
    //#endif
    private final InBox inBox;
    final OutBox draft;
    private final Trash trash;
    //#ifdef MUJMAIL_SYNC
//#     private final Sync sync;
    //#endif
    //public MailForm mailForm;// = new MailForm(this);
    private Hashtable/*<String, MailAccountPrimar>*/ mailAccounts;
    private Menu menu = null;
    private boolean initialised = false;
    //#ifdef MUJMAIL_USR_FOLDERS
    private BoxList userMailBoxes;
    //#endif

    Displayable lastDisplay; //last screen displayed before the application goes minimized, paused..
    
    private MailDBSeen mailDBSeen;
    private MailDBManager mailDBManager; 
    
    public static MujMail mujmail; //to get pointer to mujmail easier from anywhere

    /**
     * Represents the Display object. Provides more functionality than
     * javax.microedition.lcdui.Display.
     *
     * @see javax.microedition.lcdui.Display
     *
     */
    public static class MyDisplay {
        private final Display display;
        private boolean settingCurrEnabled = true;

        /**
         * Creates new instance of MyDisplay.
         * @param middlet the midlet that display object will be created.
         */
        public MyDisplay(MIDlet middlet) {
            display = Display.getDisplay(middlet);
        }

        /**
         * Disables setting current screen. This means that calling
         * {@link #setCurrent} will have no effect.
         */
        public void disableSettingCurrent() {
            settingCurrEnabled = false;
        }

        /**
         * Enables setting current screen. This means that calling
         * {@link #setCurrent} will set new screen as current.
         */
        public void enableSettingCurrent() {
            settingCurrEnabled = true;
        }

        /**
         * Sets nextDisplayable as current screen.
         *
         * @param nextDisplayable Displayable object that will be setted as
         *  current screen.
         * @see javax.microedition.lcdui.Display
         */
        public void setCurrent(Displayable nextDisplayable) {
            if (settingCurrEnabled) {
                display.setCurrent(nextDisplayable);
            }
        }
     /*   public void setCurrent(com.sun.lwuit.Form nextDisplayable) {
            nextDisplayable.show();
        }*/
        /**
         * Sets alert as current screen.
         *
         * @param alert the alert to be setted as current screen.
         * @param nextDisplayable the Displayable object that will be setted
         *  as current screen after alert.
         * @see javax.microedition.lcdui.Display
         */
        public void setCurrent(Alert alert, Displayable nextDisplayable) {
            if (settingCurrEnabled) display.setCurrent(alert, nextDisplayable);
        }
       /* public void setCurrent(LwuitUI.Alert alert, Displayable nextDisplayable) {
            alert.show();
            setCurrent(nextDisplayable);//.show();
        }*/
        /**
         * Gets current screen.
         * @return gets current screen.
         * @see javax.microedition.lcdui.Display
         */
        public Displayable getCurrent() {
            return display.getCurrent();
        }
       
    }

    public MujMail() {
        //#ifdef MUJMAIL_DEBUG_CONSOLE
//#        if (DEBUG) { DebugConsole.printlnPersistent("MujMail() - start"); }
        //#endif
        mujmail = this;
        VERSION = " v"+getAppProperty("MIDlet-Version");
        BUILD = getAppProperty("Build-Date");
         com.sun.lwuit.Display.init(this);
            try{

            Resources r1 = Resources.open("/mujMailTheme.res");
         //   if(Lang.getCurrentLanguage()!=Lang.LANG_CN)
        //    {
       //         Font.setDefaultFont(Resources.open("/font.res").getFont("Verdana12"));
        //    }
            UIManager.getInstance().setResourceBundle(r1.getL10N("Localization1", Lang.getLocaleString()));
            UIManager.getInstance().setThemeProps(r1.getTheme(r1.getThemeResourceNames()[0]));
            UIManager.getInstance().setLookAndFeel(new MyLookAndFeel());
            UIManager.getInstance().getLookAndFeel().setReverseSoftButtons(true);
            com.sun.lwuit.TextField.setClearText(Lang.get(Lang.BTN_CLR));
            }
            catch(java.io.IOException e)
            {
                e.printStackTrace();
            }
           accountSettings = new AccountSettings(this);
           alert = new MyAlert(this);
           settings = new Settings(this);
          // addressBook = new AddressBook(this);
           AddressBook.load();
//           mailForm = new MailForm(this);
//           sendMail = new SendMail(this);
        mailDBManager = new MailDBManager(); // Have to be created before any PersistentBox
        mailDBSeen = new MailDBSeen(this);

        outBox = new OutBox("OUTBOX", this, Lang.get(Lang.TB_OUTBOX));
        sentBox = new PersistentBox("SENTBOX", this, Lang.get(Lang.TB_SENTBOX));
        //#ifdef MUJMAIL_SEARCH
//        searchBox = new SearchBox(this);
        //#endif
        inBox = new InBox("INBOX", Lang.get(Lang.TB_INBOX));
        draft = new OutBox("DRAFT", this, Lang.get(Lang.TB_DRAFT));
        trash = new Trash("TRASH", this, Lang.get(Lang.TB_TRASH));
        
        //#ifdef MUJMAIL_USR_FOLDERS
        userMailBoxes = new BoxList(this);
        //#endif

        //#ifdef MUJMAIL_SYNC
//#         sync = new Sync(this, new MailAccountPrimary(MailAccount.IMAP,
//#                 "login@mujmail.org",
//#                 true,
//#                 Settings.mujMailSrvAddr,
//#                 Short.parseShort(Settings.mujMailSrvPort),
//#                 Settings.mujMailSrvLogin,
//#                 Settings.mujMailSrvPasswd,
//#                 false,
//#                 (byte)0,
//#                 false,
//#                 false,
//#                 "",
//#                 ""));
        //#endif
        
        mailAccounts = new Hashtable();
        menu = new Menu(this);
//        clearDBSelect = new ClearDBSelect(this);
        //#ifdef MUJMAIL_DEBUG_CONSOLE
//#        if (DEBUG) { DebugConsole.printlnPersistent("MujMail() - end"); };
        //#endif
        if (Settings.enableGeotagging && Settings.startGPSinit) {
            try {
                GPSStuff.getInstance();
              } catch (Exception le) {
                   //just ignore
                  le.printStackTrace();            }
        }
    }

    public void pauseApp() {
      //Anup  lastDisplay = myDisplay.getCurrent();
    }

    public void destroyApp(boolean unconditional) {
        initialised = false;
        getInBox().clearLastSafeMail();
        discServers(true);
        Logger.close();
        notifyDestroyed();
    }

    public void startApp() {
        //#ifdef MUJMAIL_DEBUG_CONSOLE
//#        if (DEBUG) { DebugConsole.printlnPersistent("MujMail.startApp - start"); };
        //#endif
        if (!settings.password.equals("")) {
            EnterInitialPasswordForm initialPassword = new EnterInitialPasswordForm();
            getDisplay().setCurrent(initialPassword);
        } else {
            myStartApplication();
        }
        //#ifdef MUJMAIL_DEBUG_CONSOLE
//#        if (DEBUG) { DebugConsole.printlnPersistent("MujMail.startApp - end"); };
        //#endif
    }

    /**
     * The form for entering the password before starting the application.
     * If the password is correct, starts the application.
     * Allows user to clear all databases and than start the application without
     * entering password.
     */
    private class EnterInitialPasswordForm extends Form implements ActionListener {
        private TextField passwordText;
        private Command okCommand = new Command("OK", Command.EXIT, 0);
        private Command cancelCommand = new Command("Exit", Command.ITEM, 1);
        private Command clearAllDBCommand = new Command("Clear all databases", Command.ITEM, 2);

        public EnterInitialPasswordForm() {
            super("Enter password");

            StringItem description = new StringItem("", "To start the application, enter the password or clear all databases with mails and settings.");
            passwordText = new TextField("Password", "", 50, TextField.PASSWORD);

            append(description);
            append(passwordText);
            addCommand(okCommand);
            addCommand(cancelCommand);
            addCommand(clearAllDBCommand);
            setCommandListener(this);
        }
        public void actionPerformed(ActionEvent ae)
        {
            com.sun.lwuit.Command c = ae.getCommand();
            if(!(c==cancelCommand||c==okCommand||c==clearAllDBCommand))
                return;
            if (c == cancelCommand) {
                destroyApp(true);
                return;
            }

            if (c == okCommand) {
                if (!Settings.password.equals(passwordText.getString())) {
                   com.sun.lwuit.Dialog.show(Lang.get(Lang.EXTRA_SONIMAIL),Lang.get(Lang.EXTRA_WRONG_PASSWORD), "", Lang.get(Lang.BTN_CANCEL));
                   passwordText.setString("");
                   return;
                }
            }

            if (c == clearAllDBCommand) {
                ClearDBSelect clearDB = new ClearDBSelect();
                clearDB.clearDataBases(true, true);
            }

        //    mainMenu();
            // start the application
            myStartApplication();
        }

        

    }

    private void myStartApplication() {
        //#ifdef MUJMAIL_DEBUG_CONSOLE
//#        if (DEBUG) { DebugConsole.printlnPersistent("MujMail.myStartApplication - start"); };
        //#endif
        try {
        boolean showAccountForm = false;
        if (!initialised) {
            //first run, initiation needed
            initialised = true;
            showAccountForm = getAccountSettings().getNumAccounts() > 0 ? false : true;

            getSettings().initSortMode();

            //#ifdef MUJMAIL_USR_FOLDERS
            // Loads mails into all mailboxe in serial way
            userMailBoxes.loadBoxes();
            //#else
//#             // We have to asynchronous load standard mail boxes
//#            
//#             Thread boxLoader = new Thread() {
//#                 public void run() {
//#                      Logger.log("Loading stareteer");
//#                     loadDefaulFolders();
//#                     Logger.log("LOADED");
//#                 }
//#             };
//#             boxLoader.start();
            //#endif

            Properties.showStartupAlerts(alert); // Show warnings about abilities of your mobile

            // We have to load accounts every time, even if no acocunt exists -> Synchronisation
            //    We have to set flag that accounts are loaded to be able add new user folders
            //    Otherwise if no account on start exists, creating User folder will block
            getAccountSettings().loadAccounts();
            // show an account form initialized by default values
            if (showAccountForm) {
               getAccountSettings().showAccount("DEFAULT_INIT");
               return;
            }
            // Toto Test
             menu.show();
          /*Anup  if ( getMenu() != null ) {
                    getMenu().setSelectedTab(Menu.ACTION);
                    getMenu().refresh(Menu.ACTION, !showAccountForm);
            } else {
                System.out.println("MujMail.myStartApplication() - menu is null");
            }*/
        } else {
  //Anup          myDisplay.setCurrent(lastDisplay);
        } //show the original display before that
        } catch ( Throwable t ) {
            System.out.println("MujMail.myStartApplication() - exception");
            t.printStackTrace();
        }
    }

    public void actionPerformed(ActionEvent evt) {
            commandAction(evt.getCommand(), Display.getDisplay(mujmail).getCurrent());
    }

    
    
    public synchronized void commandAction(com.sun.lwuit.Command c, Displayable d) {
      System.out.println("Pressed command is"+c);
        if (DEBUG) System.out.println("DEBUG MujMai.commandAction - start");
        if (d == alert.alertWindow) {
            MyAlert.AlertJob al = alert.lastJob;
            switch (al.mode) {
                case MyAlert.DB_CLEAR_CONFIRM:
                    if (c == alert.OK) {
                 //       if (al.callObject == getAddressBook()) {
                 //           getAddressBook().deleteAll(true);
               //         } else if (al.callObject == getAccountSettings()) {
                //            getAccountSettings().deleteAll(true);
                //        } else if (al.callObject == clearDBSelect) {
                   //         clearDBSelect.clearDataBases(true, false);
               //         } else {
                            ((TheBox) al.callObject).deleteAllMailsFromBoxAndDB(true);
             //           }
                    }
                    break;
                case MyAlert.DEL_CONFIRM:
                    if (c == alert.OK) {
                        if (al.callObject == getAccountSettings()) {
                            getAccountSettings().deleteAccount(getMenu().getSelectedAccount(), true);
                      //  } else if (al.callObject == getAddressBook()) {
                     //       getAddressBook().delete(getAddressBook().getSelectedIndex(), true);
                        }
                    }
                    break;
                case MyAlert.EXIT_BUSY_CONFIRM:
                    if (c == alert.OK) {
                        destroyApp(false);
                    }
                    break;
                case MyAlert.DEFAULT:
                    break;
            }
            //anup myDisplay.setCurrent(alert);
        }

    }
   
    /// Disconnect from connected servers (SMTP, POP..)
    public void discServers(boolean forcedClose) {
        SMTP.getSMTPSingleton(this).close(forcedClose, outBox);
        for (Enumeration e = getMailAccounts().elements(); e.hasMoreElements();) {
            MailAccount account = (MailAccount) e.nextElement();
            account.getProtocol().close(forcedClose, getInBox()); // Alf: Change
        }
        
        if(getInBox().isPushActive()){                
            getInBox().stopPush();
            getMenu().refreshAll(true);
        }
    }

    /** Loads defaults folders in mujMail serially.
     * (Inbox, OutBox, SentBox, Drafts, Trash)
     * Note: It's called from separate thread ( BoxList.loadingBoxesThread)
     */
    public void loadDefaulFolders() {
        getInBox().getMailDB().loadDB( getInBox());
        synchronized (getInBox().getMailDB()) {
            getInBox().getMailDB().waitForTaskEnd();
        }
        Logger.log("Inbox Loaded");
        getOutBox().getMailDB().loadDB( getOutBox());
        synchronized (getOutBox().getMailDB()) {
            getOutBox().getMailDB().waitForTaskEnd();
        }
        Logger.log("Outbox Loaded");
        getSentBox().getMailDB().loadDB( getSentBox());
        synchronized (getSentBox().getMailDB()) {
            getSentBox().getMailDB().waitForTaskEnd();
        }
        Logger.log("Sentbox Loaded");
        
        getTrash().getMailDB().loadDB( getTrash());
        synchronized (getTrash().getMailDB()) {
            getTrash().getMailDB().waitForTaskEnd();
        }
        Logger.log("Trash Loaded");

        getDraft().getMailDB().loadDB( getDraft());
        synchronized (getDraft().getMailDB()) {
            getDraft().getMailDB().waitForTaskEnd();
        }
        Logger.log("Draft Loaded");
    }        

    /**
     * Shows main menu on display
     */
    public void mainMenu() {
        getMenu().setSelectedTab(getMenu().getSelectedTab());
        getMenu().refresh(getMenu().getSelectedTab(), true);
    }

   
    
    /* ***************************
     *    getters and setters    *
     *****************************/

    public AccountSettings getAccountSettings() {
        return accountSettings;
    }

    public MyAlert getAlert() {
        return alert;
    }

    public MyDisplay getDisplay() {
        return myDisplay;
    }
    
    public PersistentBox getDraft() {
        return draft;
    }
    
    public InBox getInBox() {
        return inBox;
    }

    /**
     * TODO: do not return hashtable but make methods for accessing accounts
     * @return
     */
    public Hashtable/*<String, MailAccountPrimar>*/ getMailAccounts() {
        return mailAccounts;
    }

    public void setMailAccounts(Hashtable mailAccounts) {
        this.mailAccounts = mailAccounts;
    }
    
    public MailDBManager getMailDBManager() {
        return mailDBManager;
    }
    
    public MailDBSeen getMailDBSeen() {
        return mailDBSeen;
    }
    
    public Menu getMenu() {
        return menu;
    }
    
    public PersistentBox getOutBox() {
        return outBox;
    }
    
    //#ifdef MUJMAIL_SEARCH
//    public SearchBox getSearchBox() {
 //       return searchBox;
 //   }
    //#endif

    public PersistentBox getSentBox() {
        return sentBox;
    }

    public Settings getSettings() {
        return settings;
    }
    public void unloadSettingsForm()
    {

    }
    public void setSettings(Settings settings) {
        this.settings = settings;
    }

    //#ifdef MUJMAIL_SYNC    
//#     public Sync getSync() {
//#         return sync;
//#     }
    //#endif

    public Trash getTrash() {
        return trash;
    }

    //#ifdef MUJMAIL_USR_FOLDERS
    public BoxList getUserMailBoxes() {
        return userMailBoxes;
    }
    //#endif

}
